package tt.dz.biz.service.cardno;

import java.util.HashMap;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.util.Assert;
import tt.dz.common.AppContxtUtil;
import tt.dz.common.DzConstants;
import tt.dz.common.DzConstants.CardBIN;
import tt.dz.common.DzConstants.CardType;
import tt.dz.common.DzNumberUtil;
import tt.dz.common.LogUtil;

public final class CardNoSeqHelpHandler
{
  private static final int SEQUENCE_LENGTH = 7;
  public static final String REPLACE_TABLE_NAME_HOLDER = "$TABLE_NAME$";
  private static final String QUERY_ACCOUNT_MAX_CARD_NO_SEQ_SQL = "select max(substr(card_no, 13, 7)) from $TABLE_NAME$   where card_type=:cardType  and card_bin=:cardBin and  area_code=:areaCode and  merchant_code=:merchantCode and char_length(card_no)=20 ";
  private static final String QUERY_MAX_SEQUENCE_BY_LIKE_CARD_NO_SQL = "select  max(substr(card_no, 13, 7))  from $TABLE_NAME$ WHERE card_no like ':cardNo%';";
  private final Map<DzConstants.CardType, String> CARDTYPE_TABLE_MAP = new HashMap();
  private final Map<DzConstants.CardType, String> CARDTYPE_QUERY_SEQUNCE_MAP = new HashMap();
  private static final NamedParameterJdbcTemplate JDBC_TEMPLATE = (NamedParameterJdbcTemplate)AppContxtUtil.getBean("jdbcTemplate");
  
  private CardNoSeqHelpHandler()
  {
    Assert.notNull(JDBC_TEMPLATE, "jdbcTemplate 为空！");
    this.CARDTYPE_TABLE_MAP.put(DzConstants.CardType.ONLINE_CARD, "ms_online_account");
    this.CARDTYPE_TABLE_MAP.put(DzConstants.CardType.OFFLINE_CARD, "ms_offline_account");
    this.CARDTYPE_TABLE_MAP.put(DzConstants.CardType.IDENTITY_CARD, "ms_identity_account");
    
    this.CARDTYPE_QUERY_SEQUNCE_MAP.put(DzConstants.CardType.ONLINE_CARD, "select max(substr(t.card_no, 13, 7)) from ms_online_account t INNER JOIN ms_user_base a on a.user_id = t.user_id where a.merchant_code=:merchantCode and t.card_type=:cardType and t.card_bin=:cardBin and t.area_code=:areaCode  and char_length(card_no)=20 ");
    this.CARDTYPE_QUERY_SEQUNCE_MAP.put(DzConstants.CardType.OFFLINE_CARD, "select max(substr(card_no, 13, 7)) from ms_offline_account  where card_type=:cardType  and card_bin=:cardBin and  area_code=:areaCode and  merchant_code=:merchantCode and char_length(card_no)=20 ");
    this.CARDTYPE_QUERY_SEQUNCE_MAP.put(DzConstants.CardType.IDENTITY_CARD, "select max(substr(t.card_no, 13, 7)) from ms_identity_account t INNER JOIN ms_user_base a on a.user_id = t.user_id where a.merchant_code=:merchantCode and t.card_type=:cardType and t.card_bin=:cardBin and t.area_code=:areaCode  and char_length(card_no)=20 ");
  }
  
  private static final class CardTypeTableHolderInner
  {
    private static CardNoSeqHelpHandler HOLDER = new CardNoSeqHelpHandler();
  }
  
  public static final CardNoSeqHelpHandler instance()
  {
    return CardTypeTableHolderInner.HOLDER;
  }
  
  public double retainCardSeqCount(String currentSeqNo)
    throws NumberFormatException
  {
    if (!NumberUtils.isDigits(currentSeqNo)) {
      throw new NumberFormatException("当前致并不是有效的十进制数字");
    }
    int seqLenth = currentSeqNo.length();
    double maxSeqNumber = DzNumberUtil.getLengthMaxNumber(seqLenth);
    double curNumber = NumberUtils.toDouble(currentSeqNo, 0.0D);
    return maxSeqNumber - curNumber;
  }
  
  protected String getMaxSeqNoByBinTypeAreaMerchant(DzConstants.CardType cardType, DzConstants.CardBIN cardBin, String areaCode, String merchantCode)
  {
    CardSeqQueryVo cardSeqQueryVo = new CardSeqQueryVo(cardBin.value(), cardType.value(), areaCode, merchantCode);
    String maxSeqNo = "";
    String querySql = (String)this.CARDTYPE_QUERY_SEQUNCE_MAP.get(cardType);
    maxSeqNo = (String)JDBC_TEMPLATE.queryForObject(querySql, new BeanPropertySqlParameterSource(cardSeqQueryVo), String.class);
    LogUtil.info("当前的sequence值为" + maxSeqNo);
    return StringUtils.isEmpty(maxSeqNo) ? "0000000" : maxSeqNo;
  }
  
  protected String getMaxSeqNoByBinTypeAreaSignalCodeLikeCardNo(DzConstants.CardType cardType, DzConstants.CardBIN cardBin, String areaCode, String signalCode)
  {
    String cardNo = cardBin.value() + cardType.value() + areaCode + signalCode;
    String maxSeqNo = "";
    String tableName = (String)this.CARDTYPE_TABLE_MAP.get(cardType);
    String querySql = "select  max(substr(card_no, 13, 7))  from $TABLE_NAME$ WHERE card_no like ':cardNo%';".replace("$TABLE_NAME$", tableName).replace(":cardNo", cardNo);
    maxSeqNo = (String)JDBC_TEMPLATE.queryForObject(querySql, (BeanPropertySqlParameterSource)null, String.class);
    LogUtil.info("当前的sequence值为" + maxSeqNo);
    return StringUtils.isEmpty(maxSeqNo) ? "0000000" : maxSeqNo;
  }
  
  public int getSequenceLength()
  {
    return 7;
  }
  
  private class CardSeqQueryVo
  {
    private String cardNo;
    private String cardBin;
    private String cardType;
    private String areaCode;
    private String merchantCode;
    
    public CardSeqQueryVo() {}
    
    public CardSeqQueryVo(String cardBin, String cardType, String areaCode, String merchantCode)
    {
      this.cardBin = cardBin;
      this.cardType = cardType;
      this.areaCode = areaCode;
      this.merchantCode = merchantCode;
    }
    
    public CardSeqQueryVo(String cardNo, String cardBin, String cardType, String areaCode, String merchantCode)
    {
      this.cardNo = cardNo;
      this.cardBin = cardBin;
      this.cardType = cardType;
      this.areaCode = areaCode;
      this.merchantCode = merchantCode;
    }
    
    public String getCardBin()
    {
      return this.cardBin;
    }
    
    public void setCardBin(String cardBin)
    {
      this.cardBin = cardBin;
    }
    
    public String getCardType()
    {
      return this.cardType;
    }
    
    public void setCardType(String cardType)
    {
      this.cardType = cardType;
    }
    
    public String getAreaCode()
    {
      return this.areaCode;
    }
    
    public void setAreaCode(String areaCode)
    {
      this.areaCode = areaCode;
    }
    
    public String getMerchantCode()
    {
      return this.merchantCode;
    }
    
    public void setMerchantCode(String merchantCode)
    {
      this.merchantCode = merchantCode;
    }
    
    public String getCardNo()
    {
      return this.cardNo;
    }
    
    public void setCardNo(String cardNo)
    {
      this.cardNo = cardNo;
    }
  }
}
